use std::{
    collections::{BTreeMap, HashSet},
    io::BufRead,
};

pub fn parse_line(line: &str) -> (String, Vec<String>) {
    let a: String = line.chars().filter(|&c| c != ',' && c != ' ').collect();
    let mut _a: Vec<String> = a
        .split('"')
        .filter(|e| !e.is_empty())
        .filter_map(|s| Some(s.to_string()))
        .collect();
    let k = _a.first().unwrap().to_string();
    _a.pop();
    let v: Vec<String> = _a.drain(2..).collect();
    (k, v)
}

pub fn count_provinces() -> String {
    let file = std::fs::File::open("./district.json").unwrap();
    let mut reader = std::io::BufReader::new(file);
    let mut buf = String::new();
    let _ = reader.read_line(&mut buf);
    let mut res = String::new();
    while let Ok(n) = reader.read_line(&mut buf) {
        if n == 0 {
            break;
        }

        if buf.contains("{") {
            buf.clear();
            let mut data: BTreeMap<String, Vec<String>> = BTreeMap::new();
            while let Ok(n) = reader.read_line(&mut buf) {
                if buf.contains("}") {
                    buf.clear();
                    break;
                }
                let (k, v) = parse_line(&buf);
                data.entry(k).or_insert(v.clone()).extend(v.into_iter());
                buf.clear();
            }
            let count = count_provinces_inner(data);
            res.push_str(&count.to_string());
            res.push(',');
        }
    }
    res.pop();
    res
}

pub fn count_provinces_inner(data: BTreeMap<String, Vec<String>>) -> usize {
    let mut diff_set: Vec<HashSet<&String>> = Vec::new();
    diff_set.push(HashSet::new());
    diff_set[0].insert(data.iter().nth(0).unwrap().0);
    let _v = data.iter().nth(0).unwrap().1;
    for ele in _v {
        diff_set[0].insert(ele);
    }

    data.iter().skip(1).for_each(|(k, v)| {
        let mut flag = false;
        let mut n = 0;
        for ele in v.iter() {
            for (index, set) in diff_set.iter_mut().enumerate() {
                if set.contains(ele) {
                    n = index;
                    flag = true;
                    break;
                }
            }

            if flag {
                break;
            }
        }

        for (index, set) in diff_set.iter_mut().enumerate() {
            if set.contains(k) {
                n = index;
                flag = true;
                break;
            }
        }

        let m_set = diff_set.iter_mut().nth(n).unwrap();
        m_set.insert(k);
        v.iter().for_each(|e| {
            m_set.insert(e);
        });

        if !flag {
            let mut new_set = HashSet::new();
            new_set.insert(k);
            for ele in v {
                new_set.insert(ele);
            }
            diff_set.push(new_set);
        }
    });

    diff_set.len()
}
